package com.idopartx.phonelightning.widget

import android.content.Context
import android.graphics.*
import android.os.Parcel
import android.os.Parcelable
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import com.idopartx.phonelightning.R

class ColorPickerView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
    /**
     * 指示点颜色
     */
    private var mIndicatorColor = 0

    /**
     * 是否启用指示点
     */
    private var mIndicatorEnable = false

    /**
     * View 和 bitmapForColor 的画笔
     */
    private var paint: Paint? = null

    /**
     * 指示点专用画笔，这样可以避免 mIndicatorColor 有 alpha 时，alpha 作用于 View
     */
    private var paintForIndicator: Paint? = null
    private var linearGradient: LinearGradient? = null

    /**
     * 除去上下 padding 的端点坐标
     */
    private var mTop = 0
    private var mLeft = 0
    private var mRight = 0
    private var mBottom = 0

    /**
     * 颜色条圆角矩形边界
     */
    private val rect = Rect()

    /**
     * bitmapForIndicator 在 View 上的绘制位置
     */
    private val rectForIndicator = Rect()

    /**
     * 指示点半径
     */
    private var mRadius = 0

    /**
     * 控件方向
     */
    private var orientation: Orientation? = null

    // 不直接绘制在 View 提供的画布上的原因是：选取颜色时需要提取 Bitmap 上的颜色，View 的 Bitmap 无法获取，
    // 而且有指示点时指示点会覆盖主颜色条(重绘颜色条的颜色)
    private var bitmapForColor: Bitmap? = null
    private var bitmapForIndicator: Bitmap? = null

    /**
     * 是否需要绘制颜色条(指示点)，颜色条在选取颜色时不需要再次生成(bitmapForColor)，直接绘制就行
     */
    private var needReDrawColorTable = true
    private var needReDrawIndicator = true

    /**
     * 手指在颜色条上的坐标
     */
    private var curX = 0
    private var curY = 0
    private var colors: IntArray? = null
    private var currentColor = 0
    private var thumbRadius = 0

    /**
     * 控件方向
     */
    enum class Orientation {
        /**
         * 水平
         */
        HORIZONTAL,  // 0

        /**
         * 竖直
         */
        VERTICAL // 1
    }

    init {
        val array = context.theme.obtainStyledAttributes(
            attrs,
            R.styleable.ColorPickerView,
            defStyleAttr,
            0
        )
        mIndicatorColor = array.getColor(R.styleable.ColorPickerView_indicatorColor, Color.WHITE)
        val or = array.getInteger(R.styleable.ColorPickerView_orientation, 0)
        orientation = if (or == 0) Orientation.HORIZONTAL else Orientation.VERTICAL
        thumbRadius = array.getInteger(R.styleable.ColorPickerView_CPVThumbRadius, 10)
        mIndicatorEnable = array.getBoolean(R.styleable.ColorPickerView_indicatorEnable, true)
        array.recycle()

        bitmapForColor = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)
        bitmapForIndicator = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)

        //Android4.0（API14）之后硬件加速功能就被默认开启了,setShadowLayer 在开启硬件加速的情况下无效，需要关闭硬件加速
        setLayerType(LAYER_TYPE_SOFTWARE, null)
        paint = Paint()
        paint?.isAntiAlias = true
        paintForIndicator = Paint()
        paintForIndicator?.isAntiAlias = true
        curY = defaultSizeShort / 2
        curX = thumbRadius * 3
    }


    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        val widthMode = MeasureSpec.getMode(widthMeasureSpec)
        val widthSize = MeasureSpec.getSize(widthMeasureSpec)
        val heightMode = MeasureSpec.getMode(heightMeasureSpec)
        val heightSize = MeasureSpec.getSize(heightMeasureSpec)
        var width: Int = if (widthMode == MeasureSpec.EXACTLY) {
            widthSize
        } else { //xml中宽度设为warp_content
            suggestedMinimumWidth + paddingLeft + paddingRight
        }
        var height: Int = if (heightMode == MeasureSpec.EXACTLY) {
            heightSize
        } else {
            suggestedMinimumHeight + paddingTop + paddingBottom
        }
        width = Math.max(
            width,
            if (orientation == Orientation.HORIZONTAL) defaultSizeLong else defaultSizeShort
        )
        height = Math.max(
            height,
            if (orientation == Orientation.HORIZONTAL) defaultSizeShort else defaultSizeLong
        )
        setMeasuredDimension(width, height)
    }

    override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
        super.onLayout(changed, left, top, right, bottom)
        mTop = paddingTop
        mLeft = paddingLeft
        mBottom = measuredHeight - paddingBottom
        mRight = measuredWidth - paddingRight
        if (curX == curY || curY == Int.MAX_VALUE) {
            curX = width / 2
            curY = height / 2
        }
        calculBounds()
        setColors(*createDefaultColorTable())
        createBitmap()
        if (mIndicatorEnable) {
            needReDrawIndicator = true
        }
    }

    private fun createBitmap() {
        val hc = rect.height()
        val wc = rect.width()
        val hi = mRadius * 2
        if (bitmapForColor != null) {
            if (!bitmapForColor!!.isRecycled) {
                bitmapForColor!!.recycle()
                bitmapForColor = null
            }
        }
        if (bitmapForIndicator != null) {
            if (!bitmapForIndicator!!.isRecycled) {
                bitmapForIndicator!!.recycle()
                bitmapForIndicator = null
            }
        }
        bitmapForColor = Bitmap.createBitmap(wc, hc, Bitmap.Config.ARGB_8888)
        bitmapForIndicator = Bitmap.createBitmap(hi, hi, Bitmap.Config.ARGB_8888)
    }

    /**
     * 计算颜色条边界
     */
    private fun calculBounds() {

        /*
         * 将控件可用高度(除去上下 padding )均分为 6 份，以此计算指示点半径，颜色条宽高
         * 控件方向为 HORIZONTAL 时，从上往下依次占的份额为：
         * 1/9 留白
         * 2/9 颜色条上面部分圆
         * 3/9 颜色条宽
         * 2/9 颜色条上面部分圆
         * 1/9 留白
         */
        val average = 9

        /*
         * 每一份的高度
         */
        val each: Int
        val h = mBottom - mTop
        val w = mRight - mLeft
        var size = Math.min(w, h)
        if (orientation == Orientation.HORIZONTAL) {
            if (w <= h) { // HORIZONTAL 模式，然而宽却小于高，以 6 ：1 的方式重新计算高
                size = w / 6
            }
        } else {
            if (w >= h) {
                size = h / 6
            }
        }
        each = size / average
        mRadius = com.idopartx.phonelightning.widget.KBubbleUtils.dp2px(thumbRadius) + 3
        val t: Int
        val l: Int
        val b: Int
        val r: Int
        val s = each * 3 / 2
        if (orientation == Orientation.HORIZONTAL) {
            l = mLeft + mRadius
            r = mRight - mRadius
            t = height / 2 - com.idopartx.phonelightning.widget.KBubbleUtils.dp2px(2)
            b = height / 2 + com.idopartx.phonelightning.widget.KBubbleUtils.dp2px(2)
        } else {
            t = mTop + mRadius
            b = mBottom - mRadius
            l = width / 2 - s
            r = width / 2 + s
        }
        rect[l, t, r] = b
    }

    /**
     * 设置颜色条的渐变颜色，不支持具有 alpha 的颜色，[Color.TRANSPARENT]会被当成 [Color.BLACK]处理
     * 如果想设置 alpha ，可以在[OnColorPickerChangeListener.onColorChanged] 回调
     * 中调用{android.support.v4.graphics.ClorUtils#setAlphaComponent(int, int)}方法添加 alpha 值。
     *
     * @param colors 颜色值
     */
    fun setColors(vararg colors: Int) {
        linearGradient = null
        this.colors = colors
        if (orientation == Orientation.HORIZONTAL) {
            linearGradient = LinearGradient(
                rect.left.toFloat(), rect.top.toFloat(),
                rect.right.toFloat(), rect.top.toFloat(),
                colors,
                null,
                Shader.TileMode.CLAMP
            )
        } else {
            linearGradient = LinearGradient(
                rect.left.toFloat(), rect.top.toFloat(),
                rect.left.toFloat(), rect.bottom.toFloat(),
                colors,
                null,
                Shader.TileMode.CLAMP
            )
        }
        needReDrawColorTable = true
        invalidate()
    }

    private fun createDefaultColorTable(): IntArray {
        return intArrayOf(
            Color.parseColor("#F32400"),
            Color.parseColor("#FF8C00"),
            Color.parseColor("#E6FF01"),
            Color.parseColor("#9AFF01"),
            Color.parseColor("#46FF00"),
            Color.parseColor("#02FFA0"),
            Color.parseColor("#00FFFA"),
            Color.parseColor("#00C8FF"),
            Color.parseColor("#005AFF"),
            Color.parseColor("#0009FF"),
            Color.parseColor("#8C00FF"),
            Color.parseColor("#FF00F0"),
            Color.parseColor("#FF0A30"),
        )
    }

    override fun onDraw(canvas: Canvas) {
        if (needReDrawColorTable) {
            createColorTableBitmap()
        }
        // 绘制颜色条
        canvas.drawBitmap(bitmapForColor!!, null, rect, paint)
        if (mIndicatorEnable) {
            if (needReDrawIndicator) {
                createIndicatorBitmap()
            }

            // 绘制指示点
            rectForIndicator[curX - mRadius, curY - mRadius, curX + mRadius] = curY + mRadius
            canvas.drawBitmap(bitmapForIndicator!!, null, rectForIndicator, paint)
        }
    }

    private fun createIndicatorBitmap() {
        paintForIndicator!!.color = mIndicatorColor
        val radius = 3
        paintForIndicator!!.setShadowLayer(radius.toFloat(), 0f, 0f, Color.GRAY)
        val c = Canvas(bitmapForIndicator!!)
        c.drawCircle(
            mRadius.toFloat(),
            mRadius.toFloat(),
            (mRadius - radius).toFloat(),
            paintForIndicator!!
        )
        needReDrawIndicator = false
    }

    private fun createColorTableBitmap() {
        val c = Canvas(bitmapForColor!!)
        val rf = RectF(
            0f, 0f, bitmapForColor!!.width.toFloat(), bitmapForColor!!.height
                .toFloat()
        )

        // 圆角大小
        val r: Int = if (orientation == Orientation.HORIZONTAL) {
            bitmapForColor!!.height / 2
        } else {
            bitmapForColor!!.width / 2
        }
        // 先绘制黑色背景，否则有 alpha 时绘制不正常
        paint!!.color = Color.BLACK
        c.drawRoundRect(rf, r.toFloat(), r.toFloat(), paint!!)
        paint!!.shader = linearGradient
        c.drawRoundRect(rf, r.toFloat(), r.toFloat(), paint!!)
        paint!!.shader = null
        needReDrawColorTable = false
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        val ex = event.x.toInt()
        val ey = event.y.toInt()
        if (!inBoundOfColorTable(ex, ey)) {
            return true
        }
        if (orientation == Orientation.HORIZONTAL) {
            curX = ex
            curY = height / 2
        } else {
            curX = width / 2
            curY = ey
        }
        if (event.actionMasked == MotionEvent.ACTION_DOWN) {
            if (colorPickerChangeListener != null) {
                colorPickerChangeListener!!.onStartTrackingTouch(this)
                calcuColor()
                colorPickerChangeListener!!.onColorChanged(this, currentColor, curX, curY)
            }
        } else if (event.actionMasked == MotionEvent.ACTION_UP) { //手抬起
            if (colorPickerChangeListener != null) {
                colorPickerChangeListener!!.onStopTrackingTouch(this)
                calcuColor()
                colorPickerChangeListener!!.onColorChanged(this, currentColor, curX, curY)
            }
        } else { //按着+拖拽
            if (colorPickerChangeListener != null) {
                calcuColor()
                colorPickerChangeListener!!.onColorChanged(this, currentColor, curX, curY)
            }
        }
        invalidate()
        return true
    }

    /**
     * 获得当前指示点所指颜色
     *
     * @return 颜色值
     */
    val color: Int
        get() = calcuColor()

    private fun inBoundOfColorTable(ex: Int, ey: Int): Boolean {
        if (orientation == Orientation.HORIZONTAL) {
            if (ex <= mLeft + mRadius || ex >= mRight - mRadius) {
                return false
            }
        } else {
            if (ey <= mTop + mRadius || ey >= mBottom - mRadius) {
                return false
            }
        }
        return true
    }

    private fun calcuColor(): Int {
        val x: Int
        val y: Int
        if (orientation == Orientation.HORIZONTAL) { // 水平
            y = (rect.bottom - rect.top) / 2
            x = if (curX < rect.left) {
                1
            } else if (curX > rect.right) {
                bitmapForColor!!.width - 1
            } else {
                curX - rect.left
            }
        } else { // 竖直
            x = (rect.right - rect.left) / 2
            y = if (curY < rect.top) {
                1
            } else if (curY > rect.bottom) {
                bitmapForColor!!.height - 1
            } else {
                curY - rect.top
            }
        }
        val pixel = bitmapForColor!!.getPixel(x, y)
        currentColor = pixelToColor(pixel)
        return currentColor
    }

    private fun pixelToColor(pixel: Int): Int {
        val alpha = Color.alpha(pixel)
        val red = Color.red(pixel)
        val green = Color.green(pixel)
        val blue = Color.blue(pixel)
        return Color.argb(alpha, red, green, blue)
    }

    private var colorPickerChangeListener: OnColorPickerChangeListener? = null
    fun setOnColorPickerChangeListener(l: OnColorPickerChangeListener?) {
        colorPickerChangeListener = l
    }

    interface OnColorPickerChangeListener {
        /**
         * 选取的颜色值改变时回调
         *
         * @param picker ColorPickerView
         * @param color  颜色
         */
        fun onColorChanged(picker: ColorPickerView?, color: Int, x: Int, y: Int)

        /**
         * 开始颜色选取
         *
         * @param picker ColorPickerView
         */
        fun onStartTrackingTouch(picker: ColorPickerView?)

        /**
         * 停止颜色选取
         *
         * @param picker ColorPickerView
         */
        fun onStopTrackingTouch(picker: ColorPickerView?)
    }

//    override fun onSaveInstanceState(): Parcelable? {
//        val parcelable = super.onSaveInstanceState()
//        val ss: SavedState = SavedState(parcelable)
//        ss.selX = curX
//        ss.selY = curY
//        ss.color = bitmapForColor
//        if (mIndicatorEnable) {
//            ss.indicator = bitmapForIndicator
//        }
//        return ss
//    }
//
//    override fun onRestoreInstanceState(state: Parcelable) {
//        if (state !is SavedState) {
//            super.onRestoreInstanceState(state)
//            return
//        }
//        val ss = state
//        super.onRestoreInstanceState(ss.superState)
//        curX = ss.selX
//        curY = ss.selY
//        colors = ss.colors
//        bitmapForColor = ss.color
//        if (mIndicatorEnable) {
//            bitmapForIndicator = ss.indicator
//            needReDrawIndicator = true
//        }
//        needReDrawColorTable = true
//    }
//
//    private inner class SavedState constructor(source: Parcelable?) :
//        BaseSavedState(source) {
//        var selX = 0
//        var selY = 0
//        var colors : IntArray? = null
//        var color: Bitmap? = null
//        var indicator: Bitmap? = null
//        override fun writeToParcel(out: Parcel, flags: Int) {
//            super.writeToParcel(out, flags)
//            out.writeInt(selX)
//            out.writeInt(selY)
//            out.writeParcelable(color, flags)
//            out.writeIntArray(colors)
//            if (indicator != null) {
//                out.writeParcelable(indicator, flags)
//            }
//        }
//    }

    fun setPosition(x: Int, y: Int) {
        if (inBoundOfColorTable(x, y)) {
            curX = x
            curY = y
            if (mIndicatorEnable) {
                needReDrawIndicator = true
            }
            invalidate()
        }
    }

    /**
     * 显示默认的颜色选择器
     */
    fun showDefaultColorTable() {
        setColors(*createDefaultColorTable())
    }

    var indicatorColor: Int
        get() = mIndicatorColor
        set(color) {
            mIndicatorColor = color
            needReDrawIndicator = true
            invalidate()
        }

    fun setOrientation(orientation: Orientation?) {
        this.orientation = orientation
        needReDrawIndicator = true
        needReDrawColorTable = true
        requestLayout()
    }

    companion object {
        // 默认状态下长边与短边的比例为 6 ：1
        private const val defaultSizeShort = 70 // * 6
        private const val defaultSizeLong = 420
    }
}